﻿using System;
using System.Xml;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Collections.Specialized;
using Microsoft.SharePoint.Security;
using System.Runtime.InteropServices;
using System.Security.Permissions;

namespace Version3.SharePoint
{
    [CLSCompliant(false)]
    [Guid("552DB5B4-AA1F-40d5-85DC-CDFA22DE1D32")]
    public class FreezeDriedDataField : SPFieldMultiLineText
    {
        internal const string NO_CONTEXT = "NO*SP*CONTEXT";
        internal const string FORM_RENDER_CONTROL_STRING_KEY = "FormRenderControlString";
        internal const string FORM_RENDER_MODE_KEY = "FormRenderMode";
        internal const string COLUMN_RENDER_MODE_KEY = "ColumnRenderMode";

        internal const string FIXED_TEXT = "FixedText";
        internal const string DATA_TYPE = "DataType";
        internal const string RENDER_OBJECT = "RenderObject";
        internal const string DISPLAY_TEXT = "DisplayText";

        private static StringDictionary _NewColumnProperties = new StringDictionary();
        private string _ContextID = NO_CONTEXT;

        private string _FormRenderControlString = string.Empty;
        private string _FormRenderMode = string.Empty;
        private string _ColumnRenderMode = string.Empty;

        public FreezeDriedDataField(SPFieldCollection fields, string fieldName)
            : base(fields, fieldName)
        {
            try
            {
                _ContextID = SPContext.Current.GetHashCode().ToString();
            }
            catch
            {
                _ContextID = NO_CONTEXT;
            }
            ReadCustomProperties();
        }

        public FreezeDriedDataField(SPFieldCollection fields, string typeName, string displayName)
            : base(fields, typeName, displayName)
        {
            try
            {
                _ContextID = SPContext.Current.GetHashCode().ToString();
            }
            catch
            {
                _ContextID = NO_CONTEXT;
            }
            ReadCustomProperties();
        }

 
        public override Type FieldValueType
        {
            get
            {
                return typeof(Version3.SharePoint.FreezeDriedDataFieldValue);
            }
        }

        //Get our field control
        public override BaseFieldControl FieldRenderingControl
        {
            [SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)]
            get
            {
                BaseFieldControl fieldControl = new FreezeDriedDataFieldControl(this);
                fieldControl.FieldName = this.InternalName;
                return fieldControl;
            }
        }

        public override string GetValidatedString(object value)
        {
            string returnValue = string.Empty;
            if (value is FreezeDriedDataFieldValue)
            {
                FreezeDriedDataFieldValue castValue = (FreezeDriedDataFieldValue)value;
                returnValue = castValue.ToString();
            }
            else
            {
                if (value is string)
                {
                    returnValue = (string)value;
                }
            }
            if (this.Required && string.IsNullOrEmpty(returnValue))
            {
                //We dont let users do this so if they accidently 
                //made it required then go ahead and give them
                //a valid null FreezeDriedObject
                SPFieldMultiColumnValue nullValue = new SPFieldMultiColumnValue(2);
                returnValue = nullValue.ToString();
            }
            return returnValue;
        }

        public override object GetFieldValue(string value)
        {
            FreezeDriedDataFieldValue returnValue = new FreezeDriedDataFieldValue(value);
            return returnValue;
        }

        public override string GetFieldValueAsText(object value)
        {
            using (FreezeDriedDataFieldValue returnValue = new FreezeDriedDataFieldValue(value))
            {
                return returnValue.ToString();
            }
        }

        public override string GetFieldValueAsHtml(object value)
        {
            using (FreezeDriedDataFieldValue returnValue = new FreezeDriedDataFieldValue(value))
            {
                return returnValue.ToHTMLString();
            }
        }

        #region Configuration property management
        public override void OnAdded(SPAddFieldOptions op)
        {
            base.OnAdded(op);
            Update();
        }

        public override void Update()
        {
            WriteCustomProperties();
            base.Update();
        }

        private void ReadCustomProperties()
        {
            _FormRenderControlString = WrappedGetCustomProperty(FORM_RENDER_CONTROL_STRING_KEY, string.Empty);
            _FormRenderMode = WrappedGetCustomProperty(FORM_RENDER_MODE_KEY, string.Empty);
            _ColumnRenderMode = WrappedGetCustomProperty(COLUMN_RENDER_MODE_KEY, string.Empty);
        }

        private void WriteCustomProperties()
        {
            this.SetCustomProperty(FORM_RENDER_CONTROL_STRING_KEY, this.FormRenderControlString);
            this.SetCustomProperty(FORM_RENDER_MODE_KEY, this.FormRenderMode);
            this.SetCustomProperty(COLUMN_RENDER_MODE_KEY, this.ColumnRenderMode);

            //Apparently CAML cant access custom properties in
            //a DisplayPattern using normal queries so we will put
            //the value in an attribute of the field where all the built
            //in values are, this seems to work. I dont know if its a bug
            //of if I just dont understand how to query custom values
            //in CAML display patterns.
            
            XmlDocument xmlSchema = new XmlDocument();
            xmlSchema.LoadXml(this.SchemaXml);
            XmlNode fieldNode = xmlSchema.SelectSingleNode("/Field");
            if (null != fieldNode)
            {
                //Add our attribute to the field XML
                XmlAttribute crmAttribute = fieldNode.Attributes[COLUMN_RENDER_MODE_KEY];
                if (null == crmAttribute)
                {
                    crmAttribute = xmlSchema.CreateAttribute(COLUMN_RENDER_MODE_KEY);
                    fieldNode.Attributes.SetNamedItem(crmAttribute);
                }
                if (null != crmAttribute)
                {
                    crmAttribute.InnerText = this.ColumnRenderMode;
                }
            }
            this.SchemaXml = fieldNode.OuterXml;

            lock (_NewColumnProperties)
            {
                string contextKey = _ContextID + FORM_RENDER_CONTROL_STRING_KEY;
                if (_NewColumnProperties.ContainsKey(contextKey)) _NewColumnProperties.Remove(contextKey);

                contextKey = _ContextID + FORM_RENDER_MODE_KEY;
                if (_NewColumnProperties.ContainsKey(contextKey)) _NewColumnProperties.Remove(contextKey);

                contextKey = _ContextID + COLUMN_RENDER_MODE_KEY;
                if (_NewColumnProperties.ContainsKey(contextKey)) _NewColumnProperties.Remove(contextKey);
            }

        }

        private string WrappedGetCustomProperty(string propertyName, string defaultValue)
        {
            string returnValue = string.Empty;
            lock (_NewColumnProperties)
            {
                string contextKey = _ContextID + propertyName;
                if (_NewColumnProperties.ContainsKey(contextKey))
                {
                    returnValue = _NewColumnProperties[contextKey];
                }
            }
            if (string.IsNullOrEmpty(returnValue))
            {
                try
                {
                    object sharePointCastValue = this.GetCustomProperty(propertyName);
                    returnValue = this.GetCustomProperty(propertyName) as string;
                    if (string.IsNullOrEmpty(returnValue))
                    {
                        if (null != sharePointCastValue)
                        {
                            returnValue = sharePointCastValue.ToString();
                        }
                    }
                }
                catch
                {
                    returnValue = defaultValue;
                }
            }
            if (string.IsNullOrEmpty(returnValue)) returnValue = defaultValue;
            return returnValue;
        }

        public void SetNewColumnPropertyCacheValue(string propertyKey, string propertyValue)
        {
            lock (_NewColumnProperties)
            {
                string contextKey = _ContextID + propertyKey;
                _NewColumnProperties[contextKey] = propertyValue;
            }
        }

        public string FormRenderControlString
        {
            get
            {
                lock (_NewColumnProperties)
                {
                    string contextKey = _ContextID + FORM_RENDER_CONTROL_STRING_KEY;
                    if (_NewColumnProperties.ContainsKey(contextKey))
                    {
                        return _NewColumnProperties[contextKey];
                    }
                    else
                    {
                        return _FormRenderControlString;
                    }
                }
            }
            set
            {
                _FormRenderControlString = value;
            }
        }

        public string FormRenderMode
        {
            get
            {
                lock (_NewColumnProperties)
                {
                    string contextKey = _ContextID + FORM_RENDER_MODE_KEY;
                    if (_NewColumnProperties.ContainsKey(contextKey))
                    {
                        return _NewColumnProperties[contextKey];
                    }
                    else
                    {
                        return _FormRenderMode;
                    }
                }
            }
            set
            {
                _FormRenderMode = value;
            }
        }

        public string ColumnRenderMode
        {
            get
            {
                lock (_NewColumnProperties)
                {
                    string contextKey = _ContextID + COLUMN_RENDER_MODE_KEY;
                    if (_NewColumnProperties.ContainsKey(contextKey))
                    {
                        return _NewColumnProperties[contextKey];
                    }
                    else
                    {
                        return _ColumnRenderMode;
                    }
                }
            }
            set
            {
                _ColumnRenderMode = value;
            }
        }

        #endregion

    }


}

